﻿using System;
using System.Windows.Media;
using Redbrick.Silverlight.Common;
using System.Text;
using System.Collections.ObjectModel;
using System.Linq;
using System.Collections.Generic;
using System.Windows.Media.Imaging;

namespace Moria.Common.Model
{


	public class InventoryItem : Drawable	
	{

		#region Consts & Settings

		public const int ITEM_SINGLE_STACK_MIN = 64;
		public const int ITEM_SINGLE_STACK_MAX = 192;
		public const int ITEM_GROUP_MIN = 192;
		public const int ITEM_GROUP_MAX = 255;

		private const int MAX_TITLES = 45;
		private const int MAX_SYLLABLES = 153;

		/* Magic Treasure Generation constants				*/
		/* Note: Number of special objects, and degree of enchantments	 */
		/*	 can be adjusted here.					 */
		public const int OBJ_STD_ADJ = 125;/* Adjust STD per level * 100	       */
		public const int OBJ_STD_MIN = 7;/* Minimum STD			       */
		public const int OBJ_TOWN_LEVEL = 7;   /* Town object generation level	       */
		public const int OBJ_BASE_MAGIC = 15;  /* Base amount of magic		       */
		public const int OBJ_BASE_MAX = 70;   /* Max amount of magic		       */
		public const int OBJ_DIV_SPECIAL = 6;    /* magic_chance/#	 special magic	      */
		public const int OBJ_DIV_CURSED = 13;   /* 10*magic_chance/#  cursed items	 */
		public const int OBJECT_IDENT_SIZE = 448;

		#endregion Consts & Settings

		#region Declarations

		static ObjectDescription[] object_ident = new ObjectDescription[OBJECT_IDENT_SIZE];

		private InventoryLocation _location = InventoryLocation.None;
		private string _inscrip = string.Empty;
		private ItemFlag _flags = ItemFlag.NULL;
		private int _misc = 0;
		private int _cost = 0;
		private int _itemCount = 0;
		private int _weight = 0;
		private int _toHit = 0;
		private int _toDamage = 0;
		private int _armorClass = 0;
		private int _toArmorClass = 0;
		private int[] _damage = { 0, 0 };
		private IDFlags _identify = IDFlags.None;

		#endregion Declarations

		#region Constructor
		static InventoryItem() { InitMajic(); }

		public InventoryItem()
		{
			this.Damage = new int[2];
		}
		public InventoryItem(int ItemNdx)
		{
			Treasure from = Treasure.Table[ItemNdx];
			this.init(from);
		}
        public InventoryItem(Treasure from)
        {
            this.init(from);
        }
        public InventoryItem(InventoryItem from)
        {
            this.init(from);
        }

		public static implicit operator Treasure(InventoryItem itm)
		{
			return itm.Treasure;
		}
		public static implicit operator InventoryItem(Treasure from)
		{
			return new InventoryItem(from);
		}
		public static implicit operator InventoryItem(int ItemNdx)
		{
			return new InventoryItem(ItemNdx);
		}

		#endregion Constructor

		#region Methods

		private void init(Treasure from)
		{
			this.IsDebug = from.IsDebug;
			this.Index = Treasure.Table.IndexOf(from);
			this.SpecialName = SpecialName.NULL;
			this.inscrip = string.Empty;
			this.Flags = from.Flags;
			this.Type = from.ItemType;
			this.Misc = from.Misc;
			this.Cost = from.Cost;
			this.SubCategory = from.SubType;
			this.ItemCount = from.ItemCount;
			this.Weight = from.Weight;
			this.ToHit = from.ToHit;
			this.ToDamage = from.ToDamage;
			this.ArmorClass = from.AC;
			this.ToArmorClass = from.ToAC;
			this.Damage = new int[2];
			from.Damage.CopyTo(this.Damage, 0);
			this.Level = from.Level;
			this.Identify = 0;
		}
		private static void InitMajic()
		{
			InventoryItem.colors = new List<string>(new List<string>()
			{
				// Do not move the first three 
				"Icky Green", "Light Brown", "Clear",
				"Azure","Blue","Blue Speckled","Black","Brown","Brown Speckled","Bubbling",
				"Chartreuse","Cloudy","Copper Speckled","Crimson","Cyan","Dark Blue",
				"Dark Green","Dark Red","Gold Speckled","Green","Green Speckled","Grey",
				"Grey Speckled","Hazy","Indigo","Light Blue","Light Green","Magenta",
				"Metallic Blue","Metallic Red","Metallic Green","Metallic Purple","Misty",
				"Orange","Orange Speckled","Pink","Pink Speckled","Puce","Purple",
				"Purple Speckled","Red","Red Speckled","Silver Speckled","Smoky",
				"Tangerine","Violet","Vermilion","White","Yellow"
			}.ToList().Randomize(3));
            InventoryItem.mushrooms = new List<string>(new List<string>()
			{
			  "Blue","Black","Black Spotted","Brown","Dark Blue","Dark Green","Dark Red",
			  "Ecru","Furry","Green","Grey","Light Blue","Light Green","Plaid","Red",
			  "Slimy","Tan","White","White Spotted","Wooden","Wrinkled","Yellow",
			}.Randomize());
            InventoryItem.woods = new List<string>(new List<string>() 
			{
				"Aspen","Balsa","Banyan","Birch","Cedar","Cottonwood","Cypress","Dogwood",
				"Elm","Eucalyptus","Hemlock","Hickory","Ironwood","Locust","Mahogany",
				"Maple","Mulberry","Oak","Pine","Redwood","Rosewood","Spruce","Sycamore",
				"Teak","Walnut",
			}.Randomize());
            InventoryItem.metals = new List<string>(new List<string>
			{
			  "Aluminum","Cast Iron","Chromium","Copper","Gold","Iron","Magnesium",
			  "Molybdenum","Nickel","Rusty","Silver","Steel","Tin","Titanium","Tungsten",
			  "Zirconium","Zinc","Aluminum-Plated","Copper-Plated","Gold-Plated",
			  "Nickel-Plated","Silver-Plated","Steel-Plated","Tin-Plated","Zinc-Plated"
			}.Randomize());
            InventoryItem.rocks = new List<string>(new List<string>()
			{
			  "Alexandrite","Amethyst","Aquamarine","Azurite","Beryl","Bloodstone",
			  "Calcite","Carnelian","Corundum","Diamond","Emerald","Fluorite","Garnet",
			  "Granite","Jade","Jasper","Lapis Lazuli","Malachite","Marble","Moonstone",
			  "Onyx","Opal","Pearl","Quartz","Quartzite","Rhodonite","Ruby","Sapphire",
			  "Tiger Eye","Topaz","Turquoise","Zircon"
			}.Randomize());
            InventoryItem.amulets = new List<string>(new List<string>()
			{
			  "Amber","Driftwood","Coral","Agate","Ivory","Obsidian",
			  "Bone","Brass","Bronze","Pewter","Tortoise Shell"
			}.Randomize());
			List<string> titlz = new List<string>();

			string[] syllables = { "a","ab","ag","aks","ala","an","ankh","app", "arg","arze","ash","aus",
										   "ban","bar","bat","bek","bie","bin","bit","bjor","blu","bot","bu","byt",
										   "comp","con","cos","cre","dalf","dan","den","doe","dok","eep","el",
										   "eng","er","ere","erk","esh","evs","fa","fid","for","fri","fu","gan",
										   "gar","glen","gop","gre","ha","he","hyd","i","ing","ion","ip","ish",
										   "it","ite","iv","jo","kho","kli","klis","la","lech","man","mar","me",
										   "mi","mic","mik","mon","mung","mur","nej","nelg","nep","ner","nes",
										   "nis","nih","nin","o","od","ood","org","orn","ox","oxy","pay","pet",
										   "ple","plu","po","pot","prok","re","rea","rhov","ri","ro","rog",
										   "rok","rol","sa","san","sat","see","sef","seh","shu","ski","sna",
										   "sne","snik","sno","so","sol","sri","sta","sun","ta","tab","tem",
										   "ther","ti","tox","trol","tue","turs","u","ulk","um","un","uni","ur",
										   "val","viv","vly","vom","wah","wed","werg","wex","whon","wun","x",
										   "yerg","yp","zun"};

			for (int h = 0; h < MAX_TITLES; h++)
			{

				int k = Dice.RandInt(2) + 1;
				string title = string.Empty;
				for (int i = 0; i < k; i++)
				{
					for (int j = Dice.RandInt(2); j > 0; j--)
						title += syllables[Dice.RandInt(MAX_SYLLABLES) - 1];
					if (i < k - 1)
						title += " ";
				}
				titlz.Add(title);
			}
            InventoryItem.titles = new List<string>(titlz.Randomize());
		}

		/// <summary>
		/// was obj_desc(true)
		/// </summary>
		public override string GetDescription()
		{
			return this.GetDescription(true);
		}

		//see objdes
		enum MiscUse { Ignored = 0, Light, Flags, ZPlusses, Plusses, Charges };
		/// <summary>
		/// was obj_desc(...)
		/// </summary>
		public string GetDescription(bool pref)
		{
			int indexx = this.SubCategory & (ITEM_SINGLE_STACK_MIN - 1);
			string basenm = this.Treasure.Name;
			string modstr = string.Empty;
			string outVal = string.Empty;
			StringBuilder damstr = new StringBuilder();
			MiscUse Misc_use = MiscUse.Ignored;
			bool modify = (this.Known1 != ObjectDescription.None ? false : true);
			bool append_name = false;

			switch (this.Type)
			{
				#region
				case ItemType.MISC:
				case ItemType.CHEST:
					break;
				case ItemType.SLING_AMMO:
				case ItemType.BOLT:
				case ItemType.ARROW:
					damstr.AppendFormat(" ({0}d{1})", this.Damage[0], this.Damage[1]);
					break;
				case ItemType.LIGHT:
					Misc_use = MiscUse.Light;
					break;
				case ItemType.SPIKE:
					break;
				case ItemType.BOW:
					int tmp = -1;
					if (this.Misc == 1 || this.Misc == 2) tmp = 2;
					else if (this.Misc == 3 || this.Misc == 5) tmp = 3;
					else if (this.Misc == 4 || this.Misc == 6) tmp = 4;
					damstr.AppendFormat(" (x{0})", tmp);
					break;
				case ItemType.HAFTED:
				case ItemType.POLEARM:
				case ItemType.SWORD:
					damstr.AppendFormat(" ({0}d{1})", this.Damage[0], this.Damage[1]);
					Misc_use = MiscUse.Flags;
					break;
				case ItemType.DIGGING:
					Misc_use = MiscUse.ZPlusses;
					damstr.AppendFormat(" ({0}d{1})", this.Damage[0], this.Damage[1]);
					break;
				case ItemType.BOOTS:
				case ItemType.GLOVES:
				case ItemType.CLOAK:
				case ItemType.HELM:
				case ItemType.SHIELD:
				case ItemType.HARD_ARMOR:
				case ItemType.SOFT_ARMOR:
					break;
				case ItemType.AMULET:
					if (modify)
					{
						basenm = "& {0} Amulet";
						modstr = amulets[indexx];
					}
					else
					{
						basenm = "& Amulet";
						append_name = true;
					}
					Misc_use = MiscUse.Plusses;
					break;
				case ItemType.RING:
					if (modify)
					{
						basenm = "& {0} Ring";
						modstr = rocks[indexx];
					}
					else
					{
						basenm = "& Ring";
						append_name = true;
					}
					Misc_use = MiscUse.Plusses;
					break;
				case ItemType.STAFF:
					if (modify)
					{
						basenm = "& {0} Staff";
						modstr = woods[indexx];
					}
					else
					{
						basenm = "& Staff";
						append_name = true;
					}
					Misc_use = MiscUse.Charges;
					break;
				case ItemType.WAND:
					if (modify)
					{
						basenm = "& {0} Wand";
						modstr = metals[indexx];
					}
					else
					{
						basenm = "& Wand";
						append_name = true;
					}
					Misc_use = MiscUse.Charges;
					break;
				case ItemType.SCROLL1:
				case ItemType.SCROLL2:
					if (modify)
					{
						basenm = "& Scroll~ titled \"{0}\"";
						modstr = titles[indexx];
					}
					else
					{
						basenm = "& Scroll~";
						append_name = true;
					}
					break;
				case ItemType.POTION1:
				case ItemType.POTION2:
					if (modify)
					{
						basenm = "& {0} Potion~";
						modstr = colors[indexx];
					}
					else
					{
						basenm = "& Potion~";
						append_name = true;
					}
					break;
				case ItemType.FLASK:
					break;
				case ItemType.FOOD:
					if (modify)
					{
						if (indexx <= 15) basenm = "& {0} Mushroom~";
						else if (indexx <= 20) basenm = "& Hairy {0} Mold~";
						if (indexx <= 20) modstr = mushrooms[indexx];
					}
					else
					{
						append_name = true;
						if (indexx <= 15) basenm = "& Mushroom~";
						else if (indexx <= 20) basenm = "& Hairy Mold~";
						else append_name = false;	    /* Ordinary food does not have a name appended.  */
					}
					break;
				case ItemType.MAGIC_BOOK:
					modstr = basenm;
					basenm = "& Book~ of Magic Spells {0}";
					break;
				case ItemType.PRAYER_BOOK:
					modstr = basenm;
					basenm = "& Holy Book~ of Prayers {0}";
					break;
				case ItemType.OPEN_DOOR:
				case ItemType.CLOSED_DOOR:
				case ItemType.SECRET_DOOR:
				case ItemType.RUBBLE:
					break;
				case ItemType.GOLD:
				case ItemType.INVIS_TRAP:
				case ItemType.VIS_TRAP:
				case ItemType.UP_STAIR:
				case ItemType.DOWN_STAIR:
					return this.Name + ".";
				case ItemType.STORE_DOOR:
					return "the entrance to the " + this.Name + ".";
				default:
					return "Error in objdes()";
				#endregion
			}

			string tmp_val = string.Empty;

			if (!string.IsNullOrEmpty(modstr)) tmp_val = string.Format(basenm, modstr);
			else tmp_val = basenm;

			if (append_name) tmp_val += " of " + this.Treasure.Name;

			if (this.ItemCount != 1)
			{
				tmp_val = tmp_val.Replace("ch~", "ches")
									  .Replace("~", "s");
			}
			else
			{
				tmp_val = tmp_val.Replace("~", string.Empty);
			}

			if (!pref)
			{
				if (tmp_val.StartsWith("some")) outVal = tmp_val.Substring(5);
				else if (tmp_val.StartsWith("&")) outVal = tmp_val.Substring(2);	/* eliminate the '& ' at the beginning */
				else outVal = tmp_val;
			}
			else
			{
				if (this.SpecialName != SpecialName.NULL && this.IsKnown2)
				{
					tmp_val += " " + this.SpecialName.Description();
				}


				if (damstr.Length > 0) tmp_val += damstr;

				if (this.IsKnown2)
				{
					/* originally used %+d, but several machines don't support it */
					if (this.ShowHitDamage) tmp_val += string.Format(" ({0:+0;-0},{0:+0;-0})", this.ToHit, this.ToDamage);
					else if (this.ToHit != 0) tmp_val += string.Format(" ({0:+0;-0})", this.ToHit);
					else if (this.ToDamage != 0) tmp_val += string.Format(" ({0:+0;-0})", this.ToDamage);
				}
				/* Crowns have a zero base AC, so make a special test for them. */
				if (this.ArmorClass != 0 || this.Treasure.IsHelm)
				{
					tmp_val += " [" + this.ArmorClass;
					if (this.IsKnown2)
					{
						/* originally used %+d, but several machines don't support it */
						tmp_val += string.Format(",{0:+0;-0}", this.ToArmorClass);
					}
					tmp_val += "]";
				}
				else if ((this.ToArmorClass != 0) && this.IsKnown2)
				{
					/* originally used %+d, but several machines don't support it */
					tmp_val += string.Format(" [{0:+0;-0}]", this.ToArmorClass);
				}

				/* override defaults, check for Misc flags in the ident field */
				if (this.Identify.Has(IDFlags.NOSHOW_P1)) Misc_use = MiscUse.Ignored;
				else if (this.Identify.Has(IDFlags.SHOW_P1)) Misc_use = MiscUse.ZPlusses;

				if (Misc_use == MiscUse.Light)
				{
					tmp_val += string.Format(" with {0} turns of light", this.Misc);
				}
				else if (Misc_use == MiscUse.Ignored)
				{
					; // nothing! 
				}
				else if (this.IsKnown2)
				{
					if (Misc_use == MiscUse.ZPlusses) tmp_val += string.Format(" ({0:+0;-0})", this.Misc);
					else if (Misc_use == MiscUse.Charges) tmp_val += string.Format(" (%d charges)", this.Misc);
					else if (this.Misc != 0)
					{
						if (Misc_use == MiscUse.Plusses) tmp_val += string.Format(" ({0:+0;-0})", this.Misc);
						else if (Misc_use == MiscUse.Flags)
						{
							if (this.Flags.Has(ItemFlag.STR)) tmp_val += string.Format(" ({0:+0;-0} to STR)", this.Misc);
							else if (this.Flags.Has(ItemFlag.STEALTH)) tmp_val += string.Format(" ({0:+0;-0} to stealth)", this.Misc);
						}
					}
				}

				/* ampersand is always the first character */
				if (tmp_val.StartsWith("&"))
				{
					/* use &tmp_val[1], so that & does not appear in output */
					if (this.ItemCount > 1) outVal = "" + this.ItemCount + tmp_val.Substring(1);
					else if (this.ItemCount < 1) outVal = "no more" + tmp_val.Substring(1);
					else if (tmp_val[2].IsVowel()) outVal = "An" + tmp_val.Substring(1);
					else outVal = "A" + tmp_val.Substring(1);
				}
				else if (this.ItemCount < 1)                /* handle 'no more' case specially */
				{
					/* check for "some" at start */
					if (tmp_val.StartsWith("some")) outVal = "no more " + tmp_val.Substring(5);
					else outVal = "no more " + tmp_val; 	  /* here if no article */
				}
				else outVal = tmp_val;

				indexx = this.object_offset();
				string tmp_str = string.Empty;
				if (indexx >= 0)
				{
					indexx = (indexx <<= 6) + (this.SubCategory & (ITEM_SINGLE_STACK_MIN - 1));
					/* don't print tried string for store bought items */
					if (object_ident[indexx].Has(ObjectDescription.Tried) && !this.IsStoreBought) tmp_str = "tried ";
				}

				if (this.Identify.Has((IDFlags.MAGIK | IDFlags.EMPTY | IDFlags.DAMD)))
				{
					if (this.Identify.Has(IDFlags.MAGIK)) tmp_str += "magik ";
					if (this.Identify.Has(IDFlags.EMPTY)) tmp_str += "empty ";
					if (this.Identify.Has(IDFlags.DAMD)) tmp_str += "damned ";
				}

				if (!string.IsNullOrEmpty(this.inscrip)) tmp_str += this.inscrip;
				tmp_str = tmp_str.TrimEnd();
				if (!string.IsNullOrEmpty(tmp_str))
				{
					outVal += string.Format("{{0}}", tmp_str);
				}
				outVal += ".";
			}

			//-------------------------------//-------------------------------//
			return outVal;
		}

		public bool Has(ItemFlag flags) { return this.Flags.Has(flags); }
		public ItemFlag Mask(ItemFlag flags) { return this.Flags & flags; }
		public InventoryItem Add(ItemFlag flag)
		{
			this.Flags = this.Flags.Add<ItemFlag>(flag);
			return this;
		}
		public InventoryItem Remove(ItemFlag flag)
		{
			this.Flags = this.Flags.Remove(flag);
			return this;
		}

		public bool Has(IDFlags flags) { return this.Identify.Has(flags); }
		public InventoryItem Add(IDFlags flag)
		{
			this.Identify = this.Identify.Add<IDFlags>(flag);
			return this;
		}
		public InventoryItem Remove(IDFlags flag)
		{
			this.Identify = this.Identify.Remove(flag);
			return this;
		}

		/// <summary>
		/// was store_bought
		/// </summary>
		public void MakeStoreBought()
		{
			this.Add(IDFlags.STOREBOUGHT);
			this.known2();
		}

		/* Remove "Secret" symbol for identity of plusses			*/
		private void known2()
		{
			this.unsample();
			this.Add(IDFlags.KNOWN2);
		}

		/*	Remove an automatically generated inscription.	-CJS- */
		private void unsample()
		{
			/* used to clear ID_DAMD flag, but I think it should remain set */
			this.Remove(IDFlags.MAGIK | IDFlags.EMPTY);
			int offset = this.object_offset();
			if (offset < 0) return;
			offset <<= 6;
			int indexx = this.SubCategory & (ITEM_SINGLE_STACK_MIN - 1);
			object_ident[offset + indexx].Remove(ObjectDescription.Tried);
		}

		private int object_offset()
		{
			switch (this.Type)
			{
				case ItemType.AMULET: return (0);
				case ItemType.RING: return (1);
				case ItemType.STAFF: return (2);
				case ItemType.WAND: return (3);
				case ItemType.SCROLL1:
				case ItemType.SCROLL2: return (4);
				case ItemType.POTION1:
				case ItemType.POTION2: return (5);
				case ItemType.FOOD:
					if ((this.SubCategory & (ITEM_SINGLE_STACK_MIN - 1)) < Treasure.MAX_MUSH)
						return (6);
					return (-1);
				default: return (-1);
			}
		}

		/* Enchant a bonus based on degree desired -RAK- */
		private int m_bonus(int Base, int max_std, int level)
		{
			int stand_dev = (OBJ_STD_ADJ * level / 100) + OBJ_STD_MIN;

			/* Check for level > max_std since that may have generated an overflow.  */
			if (stand_dev > max_std || level > max_std) stand_dev = max_std;

			/* abs may be a macro, don't call it with randnor as a parameter */
			int tmp = Dice.RandNor(0, stand_dev);
			int x = (Math.Abs(tmp) / 10) + Base;

			if (x < Base) return (Base);
			return (x);
		}

		public void magic_treasure(int level)
		{
			int chance = OBJ_BASE_MAGIC + level;
			if (chance > OBJ_BASE_MAX) chance = OBJ_BASE_MAX;

			int special = chance / OBJ_DIV_SPECIAL;
			int cursed = (10 * chance) / OBJ_DIV_CURSED;


			// some objects appear multiple times in the object_list with different
			//levels, this is to make the object occur more often, however, for
			//consistency, must set the level of these duplicates to be the same
			//as the object with the lowest level 

			// Depending on treasure type, it can have certain magical properties
			switch (this.Type)
			{

				case ItemType.SHIELD:
				case ItemType.HARD_ARMOR:
				case ItemType.SOFT_ARMOR:
					MagikArmor(level, chance, special, cursed);
					break;

				case ItemType.HAFTED:
				case ItemType.POLEARM:
				case ItemType.SWORD:
					MagikMeleeWeapon(level, chance, special, cursed);
					break;

				case ItemType.BOW:
					MagikRangedWeapon(level, chance, cursed);
					break;

				case ItemType.DIGGING:
					MagikDiggingTool(level, chance);
					break;

				case ItemType.GLOVES:
					MagikGloves(level, chance, special, cursed);
					break;

				case ItemType.BOOTS:
					MagikBoots(level, chance, special, cursed);
					break;

				case ItemType.HELM:  // Helms 
					MagikHelm(level, ref chance, ref special, cursed);
					break;

				case ItemType.RING: // Rings	      
					MagikRing(level, cursed);
					break;

				case ItemType.AMULET: // Amulets	      
					MagikAmulet(level, cursed);
					break;

				// Subval should be even for store, odd for dungeon
				// Dungeon found ones will be partially charged	 
				case ItemType.LIGHT:
					MagikLight();
					break;

				case ItemType.WAND:
					MagikWand();
					break;

				case ItemType.STAFF:
					MagikStaff();
					break;

				case ItemType.CLOAK:
					MagikCloak(level, chance, special, cursed);
					break;

				case ItemType.CHEST:
					MagikChest(level);
					break;

				case ItemType.SLING_AMMO:
				case ItemType.SPIKE:
				case ItemType.BOLT:
				case ItemType.ARROW:
					MagikAmmo(level, chance, special, cursed);
					break;

				case ItemType.FOOD:
					MagikFood();
					break;

				case ItemType.SCROLL1:
					MagikScroll();
					break;

				case ItemType.POTION1:  // potions 
					MagikPotion();
					break;

				default:
					break;
			}
		}

		#region magic_treasure sub-routines

		private void MagikPotion()
		{
			if (this.SubCategory == 76)
				this.Level = 0;
		}

		private void MagikScroll()
		{
			// give all identify scrolls the same level 
			if (this.SubCategory == 67) this.Level = 1;
			// scroll of light 
			else if (this.SubCategory == 69) this.Level = 0;
			// scroll of trap detection 
			else if (this.SubCategory == 80) this.Level = 5;
			// scroll of door/stair location 
			else if (this.SubCategory == 81) this.Level = 5;
		}

		private void MagikFood()
		{
			// make sure all food rations have the same level 
			if (this.SubCategory == 90)
				this.Level = 0;
			// give all elvish waybread the same level 
			else if (this.SubCategory == 92)
				this.Level = 6;
		}

		private void MagikAmmo(int level, int chance, int special, int cursed)
		{
			if (this.Type != ItemType.SPIKE)
			{
				// always show tohit/todam values if identified 
				this.Identify |= IDFlags.SHOW_HITDAM;

				if (chance.magik())
				{
					this.ToHit += m_bonus(1, 35, level);
					this.ToDamage += m_bonus(1, 35, level);
					// see comment for weapons 
					if ((3 * special / 2).magik())
					{
						switch (Dice.RandInt(10))
						{
							case 1:
							case 2:
							case 3:
								this.SpecialName = SpecialName.SLAYING;
								this.ToHit += 5;
								this.ToDamage += 5;
								this.Cost += 20;
								break;
							case 4:
							case 5:

								this.Add(ItemFlag.FLAME_TONGUE);

								this.ToHit += 2;
								this.ToDamage += 4;
								this.SpecialName = SpecialName.FIRE;
								this.Cost += 25;
								break;
							case 6:
							case 7:
								this.Add(ItemFlag.SLAY_EVIL);
								this.ToHit += 3;
								this.ToDamage += 3;
								this.SpecialName = SpecialName.SLAY_EVIL;
								this.Cost += 25;
								break;
							case 8:
							case 9:
								this.Add(ItemFlag.SLAY_ANIMAL);
								this.ToHit += 2;
								this.ToDamage += 2;
								this.SpecialName = SpecialName.SLAY_ANIMAL;
								this.Cost += 30;
								break;
							case 10:
								this.Add(ItemFlag.SLAY_DRAGON);
								this.ToHit += 3;
								this.ToDamage += 3;
								this.SpecialName = SpecialName.DRAGON_SLAYING;
								this.Cost += 35;
								break;
						}
					}
				}
				else if (cursed.magik())
				{
					this.ToHit -= m_bonus(5, 55, level);
					this.ToDamage -= m_bonus(5, 55, level);

					this.Add(ItemFlag.CURSED);

					this.Cost = 0;
				}
			}

			this.ItemCount = 0;

			for (int i = 0; i < 7; i++)
				this.ItemCount += Dice.RandInt(6);

			//if (missile_ctr == MAX_SHORT)
			//   missile_ctr = -MAX_SHORT - 1;
			//else
			//   missile_ctr++;
			//this.Misc = missile_ctr;
		}

		private void MagikChest(int level)
		{
			switch (Dice.RandInt(level + 4))
			{
				case 1:
					this.Flags = 0;
					this.SpecialName = SpecialName.EMPTY;
					break;
				case 2:
					this.Add(ItemFlag.LOCKED_CHEST);
					this.SpecialName = SpecialName.LOCKED;
					break;
				case 3:
				case 4:
					this.Add(ItemFlag.LOSE_STR_CHESTTRAP | ItemFlag.LOCKED_CHEST);
					this.SpecialName = SpecialName.POISON_NEEDLE;
					break;
				case 5:
				case 6:
					this.Add(ItemFlag.POISON_CHESTTRAP | ItemFlag.LOCKED_CHEST);
					this.SpecialName = SpecialName.POISON_NEEDLE;
					break;
				case 7:
				case 8:
				case 9:
					this.Add(ItemFlag.PARALYSED_CHESTTRAP | ItemFlag.LOCKED_CHEST);
					this.SpecialName = SpecialName.GAS_TRAP;
					break;
				case 10:
				case 11:
					this.Add(ItemFlag.EXPLODE_CHESTTRAP | ItemFlag.LOCKED_CHEST);
					this.SpecialName = SpecialName.EXPLOSION_DEVICE;
					break;
				case 12:
				case 13:
				case 14:
					this.Add(ItemFlag.SUMMON_CHESTTRAP | ItemFlag.LOCKED_CHEST);
					this.SpecialName = SpecialName.SUMMONING_RUNES;
					break;
				case 15:
				case 16:
				case 17:
					this.Add(ItemFlag.PARALYSED_CHESTTRAP | ItemFlag.POISON_CHESTTRAP | ItemFlag.LOSE_STR_CHESTTRAP | ItemFlag.LOCKED_CHEST);
					this.SpecialName = SpecialName.MULTIPLE_TRAPS;
					break;
				default:
					this.Add(ItemFlag.SUMMON_CHESTTRAP | ItemFlag.EXPLODE_CHESTTRAP | ItemFlag.LOCKED_CHEST);
					this.SpecialName = SpecialName.MULTIPLE_TRAPS;
					break;
			}
		}

		private void MagikCloak(int level, int chance, int special, int cursed)
		{
			if (chance.magik())
			{
				if (special.magik())
				{
					if (Dice.RandInt(2) == 1)
					{
						this.SpecialName = SpecialName.PROTECTION;
						this.ToArmorClass += m_bonus(2, 40, level);
						this.Cost += 250;
					}
					else
					{
						this.ToArmorClass += m_bonus(1, 20, level);
						this.Identify |= IDFlags.SHOW_P1;
						this.Misc = Dice.RandInt(3);
						this.Add(ItemFlag.STEALTH);
						this.SpecialName = SpecialName.STEALTH;
						this.Cost += 500;
					}
				}
				else
				{
					this.ToArmorClass += m_bonus(1, 20, level);
				}
			}
			else if (cursed.magik())
			{
				int tmp = Dice.RandInt(3);
				if (tmp == 1)
				{
					this.Add(ItemFlag.AGGRAVATE);
					this.SpecialName = SpecialName.IRRITATION;
					this.ToArmorClass -= m_bonus(1, 10, level);
					this.Identify |= IDFlags.SHOW_HITDAM;
					this.ToHit -= m_bonus(1, 10, level);
					this.ToDamage -= m_bonus(1, 10, level);
					this.Cost = 0;
				}
				else if (tmp == 2)
				{
					this.SpecialName = SpecialName.VULNERABILITY;
					this.ToArmorClass -= m_bonus(10, 100, level + 50);
					this.Cost = 0;
				}
				else
				{
					this.SpecialName = SpecialName.ENVELOPING;
					this.ToArmorClass -= m_bonus(1, 10, level);
					this.Identify |= IDFlags.SHOW_HITDAM;
					this.ToHit -= m_bonus(2, 40, level + 10);
					this.ToDamage -= m_bonus(2, 40, level + 10);
					this.Cost = 0;
				}

				this.Add(ItemFlag.CURSED);

			}
		}

		private void MagikStaff()
		{
			switch (this.SubCategory)
			{
				case 0: this.Misc = Dice.RandInt(20) + 12; break;
				case 1: this.Misc = Dice.RandInt(8) + 6; break;
				case 2: this.Misc = Dice.RandInt(5) + 6; break;
				case 3: this.Misc = Dice.RandInt(20) + 12; break;
				case 4: this.Misc = Dice.RandInt(15) + 6; break;
				case 5: this.Misc = Dice.RandInt(4) + 5; break;
				case 6: this.Misc = Dice.RandInt(5) + 3; break;
				case 7: this.Misc = Dice.RandInt(3) + 1;
					this.Level = 10;
					break;
				case 8: this.Misc = Dice.RandInt(3) + 1; break;
				case 9: this.Misc = Dice.RandInt(5) + 6; break;
				case 10: this.Misc = Dice.RandInt(10) + 12; break;
				case 11: this.Misc = Dice.RandInt(5) + 6; break;
				case 12: this.Misc = Dice.RandInt(5) + 6; break;
				case 13: this.Misc = Dice.RandInt(5) + 6; break;
				case 14: this.Misc = Dice.RandInt(10) + 12; break;
				case 15: this.Misc = Dice.RandInt(3) + 4; break;
				case 16: this.Misc = Dice.RandInt(5) + 6; break;
				case 17: this.Misc = Dice.RandInt(5) + 6; break;
				case 18: this.Misc = Dice.RandInt(3) + 4; break;
				case 19: this.Misc = Dice.RandInt(10) + 12; break;
				case 20: this.Misc = Dice.RandInt(3) + 4; break;
				case 21: this.Misc = Dice.RandInt(3) + 4; break;
				case 22: this.Misc = Dice.RandInt(10) + 6;
					this.Level = 5;
					break;
				default:
					break;
			}
		}

		private void MagikWand()
		{
			switch (this.SubCategory)
			{
				case 0: this.Misc = Dice.RandInt(10) + 6; break;
				case 1: this.Misc = Dice.RandInt(8) + 6; break;
				case 2: this.Misc = Dice.RandInt(5) + 6; break;
				case 3: this.Misc = Dice.RandInt(8) + 6; break;
				case 4: this.Misc = Dice.RandInt(4) + 3; break;
				case 5: this.Misc = Dice.RandInt(8) + 6; break;
				case 6: this.Misc = Dice.RandInt(20) + 12; break;
				case 7: this.Misc = Dice.RandInt(20) + 12; break;
				case 8: this.Misc = Dice.RandInt(10) + 6; break;
				case 9: this.Misc = Dice.RandInt(12) + 6; break;
				case 10: this.Misc = Dice.RandInt(10) + 12; break;
				case 11: this.Misc = Dice.RandInt(3) + 3; break;
				case 12: this.Misc = Dice.RandInt(8) + 6; break;
				case 13: this.Misc = Dice.RandInt(10) + 6; break;
				case 14: this.Misc = Dice.RandInt(5) + 3; break;
				case 15: this.Misc = Dice.RandInt(5) + 3; break;
				case 16: this.Misc = Dice.RandInt(5) + 6; break;
				case 17: this.Misc = Dice.RandInt(5) + 4; break;
				case 18: this.Misc = Dice.RandInt(8) + 4; break;
				case 19: this.Misc = Dice.RandInt(6) + 2; break;
				case 20: this.Misc = Dice.RandInt(4) + 2; break;
				case 21: this.Misc = Dice.RandInt(8) + 6; break;
				case 22: this.Misc = Dice.RandInt(5) + 2; break;
				case 23: this.Misc = Dice.RandInt(12) + 12; break;
				default:
					break;
			}

		}

		private void MagikLight()
		{

			if ((this.SubCategory % 2) == 1)
			{
				this.Misc = Dice.RandInt(this.Misc);
				this.SubCategory -= 1;
			}

		}

		private void MagikAmulet(int level, int cursed)
		{

			if (this.SubCategory < 2)
			{
				if (cursed.magik())
				{
					this.Misc = -m_bonus(1, 20, level);
					this.Add(ItemFlag.CURSED);
					this.Cost = -this.Cost;
				}
				else
				{
					this.Misc = m_bonus(1, 10, level);
					this.Cost += this.Misc * 100;
				}
			}
			else if (this.SubCategory == 2)
			{
				this.Misc = 5 * m_bonus(1, 25, level);
				if (cursed.magik())
				{
					this.Misc = -this.Misc;
					this.Cost = -this.Cost;

					this.Add(ItemFlag.CURSED);

				}
				else
				{
					this.Cost += 50 * this.Misc;
				}
			}
			else if (this.SubCategory == 8)
			{
				// amulet of the magi is never cursed 
				this.Misc = 5 * m_bonus(1, 25, level);
				this.Cost += 20 * this.Misc;
			}

		}

		private void MagikRing(int level, int cursed)
		{

			switch (this.SubCategory)
			{
				case 0:
				case 1:
				case 2:
				case 3:
					if (cursed.magik())
					{
						this.Misc = -m_bonus(1, 20, level);
						this.Add(ItemFlag.CURSED);
						this.Cost = -this.Cost;
					}
					else
					{
						this.Misc = m_bonus(1, 10, level);
						this.Cost += this.Misc * 100;
					}
					break;
				case 4:
					if (cursed.magik())
					{
						this.Misc = -Dice.RandInt(3);
						this.Add(ItemFlag.CURSED);
						this.Cost = -this.Cost;
					}
					else
					{
						this.Misc = 1;
					}
					break;
				case 5:
					this.Misc = 5 * m_bonus(1, 20, level);
					this.Cost += this.Misc * 50;
					if (cursed.magik())
					{
						this.Misc = -this.Misc;
						this.Add(ItemFlag.CURSED);
						this.Cost = -this.Cost;
					}
					break;
				case 19:     // Increase damage	      
					this.ToDamage += m_bonus(1, 20, level);
					this.Cost += this.ToDamage * 100;
					if (cursed.magik())
					{
						this.ToDamage = -this.ToDamage;
						this.Add(ItemFlag.CURSED);
						this.Cost = -this.Cost;
					}
					break;
				case 20:     // Increase To-Hit	      
					this.ToHit += m_bonus(1, 20, level);
					this.Cost += this.ToHit * 100;
					if (cursed.magik())
					{
						this.ToHit = -this.ToHit;
						this.Add(ItemFlag.CURSED);
						this.Cost = -this.Cost;
					}
					break;
				case 21:     // Protection	      
					this.ToArmorClass += m_bonus(1, 20, level);
					this.Cost += this.ToArmorClass * 100;
					if (cursed.magik())
					{
						this.ToArmorClass = -this.ToArmorClass;
						this.Add(ItemFlag.CURSED);
						this.Cost = -this.Cost;
					}
					break;
				case 24:
				case 25:
				case 26:
				case 27:
				case 28:
				case 29:
					this.Identify |= IDFlags.NOSHOW_P1;
					break;
				case 30:     // Slaying	      
					this.Identify |= IDFlags.SHOW_HITDAM;
					this.ToDamage += m_bonus(1, 25, level);
					this.ToHit += m_bonus(1, 25, level);
					this.Cost += (this.ToHit + this.ToDamage) * 100;
					if (cursed.magik())
					{
						this.ToHit = -this.ToHit;
						this.ToDamage = -this.ToDamage;

						this.Add(ItemFlag.CURSED);

						this.Cost = -this.Cost;
					}
					break;
				default:
					break;
			}

		}

		private void MagikHelm(int level, ref int chance, ref int special, int cursed)
		{

			if ((this.SubCategory >= 6) && (this.SubCategory <= 8))
			{
				// give crowns a higher chance for magic 
				chance += (int)(this.Cost / 100);
				special += special;
			}

			if (chance.magik())
			{
				this.ToArmorClass += m_bonus(1, 20, level);
				if (special.magik())
				{
					if (this.SubCategory < 6)
					{
						int tmp = Dice.RandInt(3);
						this.Identify |= IDFlags.SHOW_P1;
						if (tmp == 1)
						{
							this.Misc = Dice.RandInt(2);
							this.Add(ItemFlag.INT);
							this.SpecialName = SpecialName.INTELLIGENCE;
							this.Cost += this.Misc * 500;
						}
						else if (tmp == 2)
						{
							this.Misc = Dice.RandInt(2);
							this.Add(ItemFlag.WIS);
							this.SpecialName = SpecialName.WISDOM;
							this.Cost += this.Misc * 500;
						}
						else
						{
							this.Misc = 1 + Dice.RandInt(4);
							this.Add(ItemFlag.INFRA);
							this.SpecialName = SpecialName.INFRAVISION;
							this.Cost += this.Misc * 250;
						}
					}
					else
					{
						switch (Dice.RandInt(6))
						{
							case 1:
								this.Identify |= IDFlags.SHOW_P1;
								this.Misc = Dice.RandInt(3);
								this.Add(ItemFlag.FREE_ACT | ItemFlag.CON | ItemFlag.DEX | ItemFlag.STR);
								this.SpecialName = SpecialName.MIGHT;
								this.Cost += 1000 + this.Misc * 500;
								break;
							case 2:
								this.Identify |= IDFlags.SHOW_P1;
								this.Misc = Dice.RandInt(3);
								this.Add(ItemFlag.CHR | ItemFlag.WIS);
								this.SpecialName = SpecialName.LORDLINESS;
								this.Cost += 1000 + this.Misc * 500;
								break;
							case 3:
								this.Identify |= IDFlags.SHOW_P1;
								this.Misc = Dice.RandInt(3);
								this.Add(ItemFlag.RES_LIGHT | ItemFlag.RES_COLD | ItemFlag.ResistAcid | ItemFlag.RES_FIRE | ItemFlag.INT);
								this.SpecialName = SpecialName.MAGI;
								this.Cost += 3000 + this.Misc * 500;
								break;
							case 4:
								this.Identify |= IDFlags.SHOW_P1;
								this.Misc = Dice.RandInt(3);
								this.Add(ItemFlag.CHR);
								this.SpecialName = SpecialName.BEAUTY;
								this.Cost += 750;
								break;
							case 5:
								this.Identify |= IDFlags.SHOW_P1;
								this.Misc = 5 * (1 + Dice.RandInt(4));
								this.Add(ItemFlag.SEE_INVIS | ItemFlag.SEARCH);
								this.SpecialName = SpecialName.SEEING;
								this.Cost += 1000 + this.Misc * 100;
								break;
							case 6:
								this.Add(ItemFlag.REGEN);
								this.SpecialName = SpecialName.REGENERATION;
								this.Cost += 1500;
								break;
						}
					}
				}
			}
			else if (cursed.magik())
			{
				this.ToArmorClass -= m_bonus(1, 45, level);

				this.Add(ItemFlag.CURSED);

				this.Cost = 0;
				if (special.magik())
					switch (Dice.RandInt(7))
					{
						case 1:
							this.Identify |= IDFlags.SHOW_P1;
							this.Misc = -Dice.RandInt(5);
							this.Add(ItemFlag.INT);
							this.SpecialName = SpecialName.STUPIDITY;
							break;
						case 2:
							this.Identify |= IDFlags.SHOW_P1;
							this.Misc = -Dice.RandInt(5);
							this.Add(ItemFlag.WIS);
							this.SpecialName = SpecialName.DULLNESS;
							break;
						case 3:

							this.Add(ItemFlag.BLIND);

							this.SpecialName = SpecialName.BLINDNESS;
							break;
						case 4:

							this.Add(ItemFlag.TIMID);

							this.SpecialName = SpecialName.TIMIDNESS;
							break;
						case 5:
							this.Identify |= IDFlags.SHOW_P1;
							this.Misc = -Dice.RandInt(5);
							this.Add(ItemFlag.STR);
							this.SpecialName = SpecialName.WEAKNESS;
							break;
						case 6:
							this.Add(ItemFlag.TELEPORT);
							this.SpecialName = SpecialName.TELEPORTATION;
							break;
						case 7:
							this.Identify |= IDFlags.SHOW_P1;
							this.Misc = -Dice.RandInt(5);
							this.Add(ItemFlag.CHR);
							this.SpecialName = SpecialName.UGLINESS;
							break;
					}
			}

		}

		private void MagikBoots(int level, int chance, int special, int cursed)
		{

			if (chance.magik())
			{
				this.ToArmorClass += m_bonus(1, 20, level);
				if (special.magik())
				{
					int tmp = Dice.RandInt(12);
					if (tmp > 5)
					{
						this.Add(ItemFlag.FFALL);
						this.SpecialName = SpecialName.SLOW_DESCENT;
						this.Cost += 250;
					}
					else if (tmp == 1)
					{
						this.Add(ItemFlag.SPEED);
						this.SpecialName = SpecialName.SPEED;
						this.Identify |= IDFlags.SHOW_P1;
						this.Misc = 1;
						this.Cost += 5000;
					}
					else // 2 - 5 
					{
						this.Add(ItemFlag.STEALTH);
						this.Identify |= IDFlags.SHOW_P1;
						this.Misc = Dice.RandInt(3);
						this.SpecialName = SpecialName.STEALTH;
						this.Cost += 500;
					}
				}
			}
			else if (cursed.magik())
			{
				int tmp = Dice.RandInt(3);
				if (tmp == 1)
				{
					this.Add(ItemFlag.SPEED);
					this.SpecialName = SpecialName.SLOWNESS;
					this.Identify |= IDFlags.SHOW_P1;
					this.Misc = -1;
				}
				else if (tmp == 2)
				{
					this.Add(ItemFlag.AGGRAVATE);
					this.SpecialName = SpecialName.NOISE;
				}
				else
				{
					this.SpecialName = SpecialName.GREAT_MASS;
					this.Weight *= 5;
				}
				this.Cost = 0;
				this.ToArmorClass -= m_bonus(2, 45, level);
				this.Add(ItemFlag.CURSED);
			}

		}

		private void MagikGloves(int level, int chance, int special, int cursed)
		{

			if (chance.magik())
			{
				this.ToArmorClass += m_bonus(1, 20, level);
				if (special.magik())
				{
					if (Dice.RandInt(2) == 1)
					{
						this.Add(ItemFlag.FREE_ACT);
						this.SpecialName = SpecialName.FREE_ACTION;
						this.Cost += 1000;
					}
					else
					{
						this.Identify |= IDFlags.SHOW_HITDAM;
						this.ToHit += 1 + Dice.RandInt(3);
						this.ToDamage += 1 + Dice.RandInt(3);
						this.SpecialName = SpecialName.SLAYING;
						this.Cost += (this.ToHit + this.ToDamage) * 250;
					}
				}
			}
			else if (cursed.magik())
			{
				if (special.magik())
				{
					if (Dice.RandInt(2) == 1)
					{
						this.Add(ItemFlag.DEX);
						this.SpecialName = SpecialName.CLUMSINESS;
					}
					else
					{
						this.Add(ItemFlag.STR);
						this.SpecialName = SpecialName.WEAKNESS;
					}
					this.Identify |= IDFlags.SHOW_P1;
					this.Misc = -m_bonus(1, 10, level);
				}
				this.ToArmorClass -= m_bonus(1, 40, level);
				this.Add(ItemFlag.CURSED);
				this.Cost = 0;
			}

		}

		private void MagikDiggingTool(int level, int chance)
		{

			// always show tohit/todam values if identified 
			this.Identify |= IDFlags.SHOW_HITDAM;
			if (chance.magik())
			{
				int tmp = Dice.RandInt(3);
				if (tmp < 3)
				{
					this.Misc += m_bonus(0, 25, level);
				}
				else
				{
					// a cursed digging tool 
					this.Misc = -m_bonus(1, 30, level);
					this.Cost = 0;
					this.Add(ItemFlag.CURSED);
				}
			}

		}

		private void MagikRangedWeapon(int level, int chance, int cursed)
		{

			// always show tohit/todam values if identified 
			this.Identify.Add(IDFlags.SHOW_HITDAM);
			if (chance.magik())
			{
				this.ToHit += m_bonus(1, 30, level);
				this.ToDamage += m_bonus(1, 20, level); // add damage. -CJS- 
			}
			else if (cursed.magik())
			{
				this.ToHit -= m_bonus(1, 50, level);
				this.ToDamage -= m_bonus(1, 30, level); // add damage. -CJS- 
				this.Add(ItemFlag.CURSED);
				this.Cost = 0;
			}

		}

		private void MagikMeleeWeapon(int level, int chance, int special, int cursed)
		{

			// always show tohit/todam values if identified 
			this.Identify.Add(IDFlags.SHOW_HITDAM);
			if (chance.magik())
			{
				this.ToHit += m_bonus(0, 40, level);
				// Magical damage bonus now proportional to weapon base damage 
				int tmp = this.Damage[0] * this.Damage[1];
				this.ToDamage += m_bonus(0, 4 * tmp, tmp * level / 10);
				// the 3*special/2 is needed because weapons are not as common as
				//before change to treasure distribution, this helps keep same
				//number of ego weapons same as before, see also missiles 
				if ((3 * special / 2).magik())
					switch (Dice.RandInt(16))
					{
						case 1:	// Holy Avenger	 
							this.Add(ItemFlag.SEE_INVIS | ItemFlag.SUST_STAT | ItemFlag.SLAY_UNDEAD | ItemFlag.SLAY_EVIL | ItemFlag.STR);
							this.ToHit += 5;
							this.ToDamage += 5;
							this.ToArmorClass += Dice.RandInt(4);
							// the value in Misc is used for strength increase 
							// Misc is also used for sustain stat 
							this.Misc = Dice.RandInt(4);
							this.SpecialName = SpecialName.HA;
							this.Cost += this.Misc * 500;
							this.Cost += 10000;
							break;
						case 2:	// Defender	 
							this.Add(ItemFlag.FFALL | ItemFlag.RES_LIGHT | ItemFlag.SEE_INVIS | ItemFlag.FREE_ACT | ItemFlag.RES_COLD | ItemFlag.ResistAcid | ItemFlag.RES_FIRE | ItemFlag.REGEN | ItemFlag.STEALTH);
							this.ToHit += 3;
							this.ToDamage += 3;
							this.ToArmorClass += 5 + Dice.RandInt(5);
							this.SpecialName = SpecialName.DF;
							// the value in Misc is used for stealth 
							this.Misc = Dice.RandInt(3);
							this.Cost += this.Misc * 500;
							this.Cost += 7500;
							break;
						case 3:
						case 4:	 // Slay Animal  
							this.Add(ItemFlag.SLAY_ANIMAL);
							this.ToHit += 3;
							this.ToDamage += 3;
							this.SpecialName = SpecialName.SA;
							this.Cost += 5000;
							break;
						case 5:
						case 6:	// Slay Dragon	 
							this.Add(ItemFlag.SLAY_DRAGON);
							this.ToHit += 3;
							this.ToDamage += 3;
							this.SpecialName = SpecialName.SD;
							this.Cost += 4000;
							break;
						case 7:
						case 8:	  // Slay Evil	   
							this.Add(ItemFlag.SLAY_EVIL);
							this.ToHit += 3;
							this.ToDamage += 3;
							this.SpecialName = SpecialName.SE;
							this.Cost += 4000;
							break;
						case 9:
						case 10:	 // Slay Undead	  
							this.Add(ItemFlag.SEE_INVIS | ItemFlag.SLAY_UNDEAD);
							this.ToHit += 2;
							this.ToDamage += 2;
							this.SpecialName = SpecialName.SU;
							this.Cost += 3000;
							break;
						case 11:
						case 12:
						case 13:   // Flame Tongue  
							this.Add(ItemFlag.FLAME_TONGUE);
							this.ToHit++;
							this.ToDamage += 3;
							this.SpecialName = SpecialName.FT;
							this.Cost += 2000;
							break;
						case 14:
						case 15:
						case 16:   // Frost Brand   
							this.Add(ItemFlag.FROST_BRAND);
							this.ToHit++;
							this.ToDamage++;
							this.SpecialName = SpecialName.FB;
							this.Cost += 1200;
							break;
					}
			}
			else if (cursed.magik())
			{
				this.ToHit -= m_bonus(1, 55, level);
				// Magical damage bonus now proportional to weapon base damage 
				int tmp = this.Damage[0] * this.Damage[1];
				this.ToDamage -= m_bonus(1, 11 * tmp / 2, tmp * level / 10);
				this.Add(ItemFlag.CURSED);
				this.Cost = 0;
			}

		}

		private void MagikArmor(int level, int chance, int special, int cursed)
		{

			if (chance.magik())
			{
				this.ToArmorClass += m_bonus(1, 30, level);
				if (special.magik())
					switch (Dice.RandInt(9))
					{
						case 1:
							this.Add(ItemFlag.RES_LIGHT | ItemFlag.RES_COLD | ItemFlag.ResistAcid | ItemFlag.RES_FIRE);
							this.SpecialName = SpecialName.R;
							this.ToArmorClass += 5;
							this.Cost += 2500;
							break;
						case 2:	 // Resist Acid	  
							this.Add(ItemFlag.ResistAcid);
							this.SpecialName = SpecialName.RA;
							this.Cost += 1000;
							break;
						case 3:
						case 4:	 // Resist Fire	  
							this.Add(ItemFlag.RES_FIRE);
							this.SpecialName = SpecialName.RF;
							this.Cost += 600;
							break;
						case 5:
						case 6:	// Resist Cold	 
							this.Add(ItemFlag.RES_COLD);
							this.SpecialName = SpecialName.RC;
							this.Cost += 600;
							break;
						case 7:
						case 8:
						case 9:  // Resist Lightning
							this.Add(ItemFlag.RES_LIGHT);
							this.SpecialName = SpecialName.RL;
							this.Cost += 500;
							break;
					}
			}
			else if (cursed.magik())
			{
				this.ToArmorClass -= m_bonus(1, 40, level);
				this.Cost = 0;
				this.Add(ItemFlag.CURSED);
			}

		}

		#endregion magic_treasure sub-routines

		private int item_value()
		{
			int value = this.Cost;
			/* don't purchase known cursed items */
			if (this.Identify.Is(IDFlags.DAMD))
			{
				value = 0;
			}
			else if (this.Treasure.IsWeapon || this.Treasure.IsArmor)
			{
				if (!this.IsKnown2)
				{
					value = this.Treasure.Cost;
				}
				else if (this.Treasure.IsWeapon)
				{
					if (this.ToHit < 0) value = 0;
					else if (this.ToDamage < 0) value = 0;
					else if (this.ToArmorClass < 0) value = 0;
					else value = this.Cost + (this.ToHit + this.ToDamage + this.ToArmorClass) * 100;
				}
				else
				{
					if (this.ToArmorClass < 0) value = 0;
					else value = this.Cost + this.ToArmorClass * 100;
				}
			}
			else if (this.Treasure.IsAmmo)
			{
				if (!this.IsKnown2)
				{
					value = this.Treasure.Cost;
				}
				else
				{
					if (this.ToHit < 0) value = 0;
					else if (this.ToDamage < 0) value = 0;
					else if (this.ToArmorClass < 0) value = 0;
					else value = this.Cost + (this.ToHit + this.ToDamage + this.ToArmorClass) * 5; // use 5, because missiles generally appear in groups of 20, 
					//so 20 * 5 == 100, which is comparable to weapon bonus above 
				}
			}
			else if (this.Treasure.IsScroll || this.Treasure.IsPotion)
			{
				if (this.Known1 == 0)
					value = 20;
			}
			else if (this.Treasure.IsFood)
			{
				if ((this.SubCategory < (InventoryItem.ITEM_SINGLE_STACK_MIN + Treasure.MAX_MUSH)) && (this.Known1 == 0))
				{
					value = 1;
				}
			}
			else if (this.Treasure.IsAmulet || this.Treasure.IsRing)
			{
				if ((this.Known1 == 0))
				{
					/* player does not know what type of ring/amulet this is */
					value = 45;
				}
				else if (!IsKnown2)
				{   /* player knows what type of ring, but does not know whether it is
					   //cursed or not, if refuse to buy cursed objects here, then
					   //player can use this to 'identify' cursed objects */
					value = this.Treasure.Cost;
				}
			}
			else if (this.Treasure.IsStaff || this.Treasure.IsWand)
			{
				if (this.Known1 == 0)
				{
					if (this.Type == ItemType.WAND) value = 50;
					else value = 70;
				}
				else if (this.IsKnown2)
				{
					value = this.Cost + (this.Cost / 20) * this.Misc;
				}
			}
			else if (this.Treasure.IsDigging)
			{
				if (!this.IsKnown2)
				{
					value = this.Treasure.Cost;
				}
				else
				{
					if (this.Misc < 0)
					{
						value = 0;
					}
					else
					{
						/* some digging tools start with non-zero p1 values, so only
					  // multiply the plusses by 100, make sure result is positive */
						value = this.Cost + (this.Misc - this.Treasure.Misc) * 100;
						if (value < 0)
							value = 0;
					}
				}
			}

			/* multiply value by number of items if it is a group stack item */
			if (this.SubCategory > ITEM_GROUP_MIN) /* do not include torches here */
				value = value * this.ItemCount;
			return (value);
		}
		internal void store_bought()
		{
			this.Add(IDFlags.STOREBOUGHT);
			this.known2();
		}

		#endregion Methods

		#region Events


		#endregion Events

		#region Properties

		public Treasure Treasure { get { return Treasure.Table[this.Index]; } }

		public string Name { get { return this.Treasure.Name; } }
		public int Index { get; set; }		// Index to Treasure.Table 
		public SpecialName SpecialName { get; set; }		// Object special Name  

		/// was tval
		public ItemType Type { get;  set; }		// Item ItemType 

		//public int Symbol { get; set; }		// Character representation
		public int SubCategory { get; set; }		// Sub-category ItemCount	
		public int Level { get; set; }		// Level item first found 

		public InventoryLocation Location
		{
			get { return this._location; }
			set
			{
				if (value == this._location) return;
				this._location = value;
				this.RaisePropertyChanged(() => this.Location);
			}
		}
		public string inscrip
		{
			get { return this._inscrip; }
			set
			{
				if (value == this._inscrip) return;
				this._inscrip = value;
				this.RaisePropertyChanged(() => this.inscrip);
			}
		}		// Object inscription   
		public ItemFlag Flags
		{
			get { return this._flags; }
			set
			{
				if (value == this._flags) return;
				this._flags = value;
				this.RaisePropertyChanged(() => this.Flags);
			}
		}		// Special flags	
		public int Misc
		{
			get { return this._misc; }
			set
			{
				if (value == this._misc) return;
				this._misc = value;
				this.RaisePropertyChanged(() => this.Misc);
			}
		}				// Misc. use variable	
		public int Cost
		{
			get { return this._cost; }
			set
			{
				if (value == this._cost) return;
				this._cost = value;
				this.RaisePropertyChanged(() => this.Cost);
			}
		}				// Cost of item		
		public int ItemCount
		{
			get { return this._itemCount; }
			set
			{
				if (value == this._itemCount) return;
				this._itemCount = value;
				this.RaisePropertyChanged(() => this.ItemCount);
			}
		}			// Number of Items	
		public int Weight
		{
			get { return this._weight; }
			set
			{
				if (value == this._weight) return;
				this._weight = value;
				this.RaisePropertyChanged(() => this.Weight);
			}
		}				// Weight		
		public int ToHit
		{
			get { return this._toHit; }
			set
			{
				if (value == this._toHit) return;
				this._toHit = value;
				this.RaisePropertyChanged(() => this.ToHit);
			}
		}				// Plusses to hit	
		public int ToDamage
		{
			get { return this._toDamage; }
			set
			{
				if (value == this._toDamage) return;
				this._toDamage = value;
				this.RaisePropertyChanged(() => this.ToDamage);
			}
		}			// Plusses to Damage	
		public int ArmorClass
		{
			get { return this._armorClass; }
			set
			{
				if (value == this._armorClass) return;
				this._armorClass = value;
				this.RaisePropertyChanged(() => this.ArmorClass);
			}
		}		// Normal AC		
		/// was toac
		public int ToArmorClass
		{
			get { return this._toArmorClass; }
			set
			{
				if (value == this._toArmorClass) return;
				this._toArmorClass = value;
				this.RaisePropertyChanged(() => this.ToArmorClass);
			}
		}		// Plusses to AC	
		public int[] Damage
		{
			get { return this._damage; }
			private set
			{
				if (value == this._damage) return;
				this._damage = value;
				this.RaisePropertyChanged(() => this.Damage);
			}
		}			// Damage when hits	
		public IDFlags Identify
		{
			get { return this._identify; }
			set
			{
				if (value == this._identify) return;
				this._identify = value;
				this.RaisePropertyChanged(() => this.Identify);
			}
		}		// Identify information 	


		public bool IsCursed { get { return this.Has(ItemFlag.CURSED); } }
		public bool IsSlowDigest { get { return this.Has(ItemFlag.SLOW_DIGEST); } }
		public bool IsAggravate { get { return this.Has(ItemFlag.AGGRAVATE); } }
		public bool IsTeleport { get { return this.Has(ItemFlag.TELEPORT); } }
		public bool IsRegeneration { get { return this.Has(ItemFlag.REGEN); } }
		public bool IsResistFire { get { return this.Has(ItemFlag.RES_FIRE); } }
		public bool IsResistAcid { get { return this.Has(ItemFlag.ResistAcid); } }
		public bool IsResistCold { get { return this.Has(ItemFlag.RES_COLD); } }
		public bool IsFreeAction { get { return this.Has(ItemFlag.FREE_ACT); } }
		public bool IsSeeInvisible { get { return this.Has(ItemFlag.SEE_INVIS); } }
		public bool IsResistLightning { get { return this.Has(ItemFlag.RES_LIGHT); } }
		public bool IsFeatherFall { get { return this.Has(ItemFlag.FFALL); } }
		public bool IsSustainStr { get { return this.Has(ItemFlag.SUST_STAT) && this.Misc == 1; } }
		public bool IsSustainInt { get { return this.Has(ItemFlag.SUST_STAT) && this.Misc == 2; } }
		public bool IsSustainWis { get { return this.Has(ItemFlag.SUST_STAT) && this.Misc == 3; } }
		public bool IsSustainCon { get { return this.Has(ItemFlag.SUST_STAT) && this.Misc == 4; } }
		public bool IsSustainDex { get { return this.Has(ItemFlag.SUST_STAT) && this.Misc == 5; } }
		public bool IsSustainChr { get { return this.Has(ItemFlag.SUST_STAT) && this.Misc == 6; } }
		public bool IsHiddenTrap { get { return this.Treasure.IsVisibleTrap; } }
		public bool IsVisibleTrap { get { return this.Type == ItemType.VIS_TRAP; } }
		public bool IsRubble { get { return this.Treasure.IsRubble; } }
		public bool IsStoreDoor { get { return this.Treasure.IsStoreDoor; } }
		public bool IsTrap { get { return this.IsVisibleTrap || this.IsHiddenTrap || this.IsStoreDoor; } }
		public bool IsChest { get { return this.Type == ItemType.CHEST; } }
		public bool HasTrap { get { return (int)this.Mask(ItemFlag.TRAPPED_CHEST) > 1; } }
		public bool IsSecretDoor { get { return this.Treasure.IsSecretDoor; } }
		public bool IsGold { get { return this.Treasure.IsGold; } }

		/// <summary>
		/// this.ShowHitDamage
		/// </summary>
		public bool ShowHitDamage { get { return this.Identify.Has(IDFlags.SHOW_HITDAM); } }


		/// <summary>
		/// was known2_p
		/// </summary>
		public bool IsKnown2
		{
			get {	return (this.Identify.Is(IDFlags.KNOWN2));			}
			set { if (value) this.Add(IDFlags.KNOWN2); else this.Remove(IDFlags.KNOWN2); }
		}

		/// <summary>
		/// known1_p
		/// </summary>
		public ObjectDescription Known1
		{
			get
			{
				int offset = this.object_offset();
				/* Items which don't have a 'color' are always known1, so that they can  be carried in order in the inventory.  */
				if (offset < 0) return ObjectDescription.Known1;
				if (this.IsStoreBought) return ObjectDescription.Known1;
				offset <<= 6;
				int indexx = this.SubCategory & (ITEM_SINGLE_STACK_MIN - 1);
				return (object_ident[offset + indexx] & ObjectDescription.Known1);
			}
		}

		public int Value { get { return this.item_value(); } }
		/// <summary>
		/// store_bought_p
		/// </summary>
		private bool IsStoreBought { get { return this.Identify.Has(IDFlags.STOREBOUGHT); } }

		#endregion Properties

		#region stuff

		private static List<string> colors;
		private static List<string> mushrooms;
		private static List<string> woods;
		private static List<string> metals;
		private static List<string> rocks;
		private static List<string> amulets;
		private static List<string> titles;



		#endregion

	}
}
